using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using ICSharpCode.AvalonEdit.Search;
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
using System.Xml;
using 雷赛板卡上位机.Models;

namespace 雷赛板卡上位机.Utilities;

public sealed class AvalonEditBehaviour : Behavior<TextEditor>
{
    public static readonly DependencyProperty IsScrollToEndProperty =
        DependencyProperty.Register("IsScrollToEnd", typeof(bool), typeof(AvalonEditBehaviour), new PropertyMetadata(false));

    public static readonly DependencyProperty GiveMeTheTextProperty =
        DependencyProperty.Register("GiveMeTheText", typeof(string), typeof(AvalonEditBehaviour),
            new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, PropertyChangedCallback));
    // 定义依赖属性
    public static readonly DependencyProperty MouseWheelCommandProperty =
        DependencyProperty.Register(
            nameof(MouseWheelCommand),
            typeof(ICommand),
            typeof(AvalonEditBehaviour),
            new PropertyMetadata(null));

    public static readonly DependencyProperty FoldingServiceProperty =
        DependencyProperty.Register(nameof(FoldingService),
            typeof(ICommand),
            typeof(AvalonEditBehaviour),
            new PropertyMetadata(null));

    public ICommand FoldingService
    {
        get => (ICommand)GetValue(FoldingServiceProperty); set => SetValue(FoldingServiceProperty, value);
    }

    public bool IsScrollToEnd
    {
        get { return (bool)GetValue(IsScrollToEndProperty); }
        set
        {
            SetValue(IsScrollToEndProperty, value);
        }
    }
    public string GiveMeTheText
    {
        get { return (string)GetValue(GiveMeTheTextProperty); }
        set { SetValue(GiveMeTheTextProperty, value); }
    }

    public ICommand MouseWheelCommand
    {
        get => (ICommand)GetValue(MouseWheelCommandProperty);
        set => SetValue(MouseWheelCommandProperty, value);
    }

    private CompletionWindow _completionWindow;
    protected override void OnAttached()
    {
        base.OnAttached();
        if (AssociatedObject != null)
        {
            AssociatedObject.TextChanged += AssociatedObjectOnTextChanged;
            AssociatedObject.PreviewMouseWheel += AssociatedObject_MouseWheel;
            AssociatedObject.TextArea.TextEntered += TextArea_TextEntered;
            AssociatedObject.Loaded += AssociatedObject_Loaded;
        }

    }



    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (AssociatedObject != null)
        {
            AssociatedObject.TextChanged -= AssociatedObjectOnTextChanged;
            AssociatedObject.PreviewMouseWheel -= AssociatedObject_MouseWheel;
            AssociatedObject.TextArea.TextEntered -= TextArea_TextEntered;
            AssociatedObject.Loaded -= AssociatedObject_Loaded;

        }
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        var text = sender as TextEditor;
        //快速搜索功能
        if (text != null)
        {
            SearchPanel.Install(text.TextArea);
            //设置语法规则
            string name = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".Lua.xshd";
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            using (System.IO.Stream s = assembly.GetManifestResourceStream(name))
            {
                using (XmlTextReader reader = new XmlTextReader(s))
                {
                    var xshd = HighlightingLoader.LoadXshd(reader);
                    text.SyntaxHighlighting = HighlightingLoader.Load(xshd, HighlightingManager.Instance);
                }
            }
            if (FoldingService is not null && FoldingService.CanExecute(sender))
            {
                FoldingService.Execute(sender);
            }
            
        }
    }

    private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
    {
        //var text = sender as TextArea;

        //if(text is not null)
        //{
        //    switch (e.Text)
        //    {
        //        case "l":
        //            PromptText(text, "local");
        //            break;
        //        case "r":
        //            PromptText(text, "return");
        //            break;
        //        case "f":
        //            PromptText(text, "for");
        //            PromptText(text, "function");
        //            break;
        //        case "w":
        //            PromptText(text, "while");
        //            break;
        //    }

        //}
    }

    private void AssociatedObject_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (MouseWheelCommand != null && MouseWheelCommand.CanExecute(e))
        {

            MouseWheelCommand.Execute(new object[] { sender, e });
        }
    }
    private void AssociatedObjectOnTextChanged(object sender, EventArgs eventArgs)
    {
        var textEditor = sender as TextEditor;
        if (textEditor != null)
        {
            if (textEditor.Document != null)
                GiveMeTheText = textEditor.Document.Text;
            if (IsScrollToEnd)
            {
                textEditor.ScrollToEnd();
            }
           
        }
    }

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        var behavior = dependencyObject as AvalonEditBehaviour;
        if (behavior != null && behavior.AssociatedObject != null)
        {
            var editor = behavior.AssociatedObject as TextEditor;
            if (editor.Document != null && dependencyPropertyChangedEventArgs.NewValue != null)
            {

                behavior.Dispatcher.Invoke(() =>
                {
                    var caretOffset = editor.CaretOffset;
                    editor.Document.Text = dependencyPropertyChangedEventArgs.NewValue.ToString();
                    if (editor.CaretOffset >= caretOffset)
                    {
                        editor.CaretOffset = caretOffset;
                    }
                });
            }
        }
    }
}

